﻿using Exhort.Utility.Entities;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace Exhort.Backstage.Components
{
    public static class Authentication
    {
        private const string UserIDKey = "WORK-USERID";
        private const string UserNameKey = "WORK-USERNAME";
        private const string IsSuperKey = "WORK-ISSUPER";

        /// <summary>
        /// 登陆超时 Json 信息
        /// </summary>
        private static string timeoutJson = ServiceResult.Serialize(ServiceResultCode.Logout);

        /// <summary>
        /// 验证请求类型
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private static bool IsAjaxRequest(HttpRequest request)
        {
            return string.Equals(request.Query["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal)
                || string.Equals(request.Headers["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal);
        }

        /// <summary>
        /// 此函数太过厉害暂时没有名称
        /// </summary>
        /// <param name="services"></param>
        /// <param name="scheme"></param>
        /// <param name="url"></param>
        /// <param name="formRedirect">设置表单提交类型是否页面跳转</param>
        /// <returns></returns>
        public static AuthenticationBuilder AddAuthentication(this IServiceCollection services, string scheme, string url, bool formRedirect)
        {
            // 设置默认方案名称
            var builder = services.AddAuthentication(opts => { opts.DefaultScheme = scheme; });

            // 设置 Cookie 方案
            builder.AddCookie(scheme, opts =>
            {
                // 设置 Cookie 只读模式
                opts.Cookie.HttpOnly = true;
                // 重写跳转到登录页事件
                opts.Events.OnRedirectToLogin = context =>
                {
                    if (IsAjaxRequest(context.Request) || (!formRedirect && context.Request.HasFormContentType))
                    {
                        context.Response.Clear();
                        context.Response.StatusCode = 400;
                        return context.Response.WriteAsync(timeoutJson);
                    }
                    // 非 Ajax 请求情况下正常跳转登录页面
                    context.Response.Redirect(url); return Task.CompletedTask;
                };
            });

            return builder;
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="context"></param>
        /// <param name="scheme"></param>
        /// <param name="userid"></param>
        /// <param name="username"></param>
        public static async Task<Task> SignInAsync(this HttpContext context, string scheme, string userid, string username, bool isSuper)
        {
            var claims = new List<Claim> {
                new Claim(UserIDKey, userid),
                new Claim(UserNameKey, username),
                new Claim(IsSuperKey, isSuper.ToString())
            };
            var claimsIdentity = new ClaimsIdentity(claims, scheme);
            var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);

            await context.SignInAsync(scheme, claimsPrincipal, new AuthenticationProperties()
            {
                AllowRefresh = true,
                IsPersistent = true,
                ExpiresUtc = DateTime.UtcNow.AddHours(2)
            });

            return Task.CompletedTask;
        }

        /// <summary>
        /// 用户编号
        /// </summary>
        /// <param name="claimsPrincipal"></param>
        /// <returns></returns>
        public static string GetUserID(this ClaimsPrincipal claimsPrincipal)
        {
            return claimsPrincipal.FindFirst(UserIDKey).Value;
        }

        /// <summary>
        /// 用户名
        /// </summary>
        /// <param name="claimsPrincipal"></param>
        /// <returns></returns>
        public static string GetUserName(this ClaimsPrincipal claimsPrincipal)
        {
            return claimsPrincipal.FindFirst(UserNameKey).Value;
        }

        /// <summary>
        /// 是否超级管理员
        /// </summary>
        /// <param name="claimsPrincipal"></param>
        /// <returns></returns>
        public static bool GetIsSuper(this ClaimsPrincipal claimsPrincipal)
        {
            return Convert.ToBoolean(claimsPrincipal.FindFirst(IsSuperKey).Value);
        }
    }
}